package tech.mhuang.pacebox.springboot.core.okhttp;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import tech.mhuang.pacebox.core.exception.BusinessException;
import tech.mhuang.pacebox.core.util.ObjectUtil;
import tech.mhuang.pacebox.core.util.StringUtil;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.KeyStore;
import java.security.SecureRandom;

/**
 * okhttp 工具类
 *
 * @author mhuang
 * @since 1.1.0
 */
public class OkhttpClientUtil {

    /**
     * 生成OkhttpClient
     *
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient() {
        return genOkHttpClient(null, 0);
    }

    /**
     * 根据拦截器生成OkhttpClient
     *
     * @param interceptor 拦截器
     * @return OkHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(Interceptor interceptor) {
        return genOkHttpClient(null, 0, interceptor);
    }

    /**
     * 根据代理生成okHttpClient
     *
     * @param proxyHost 代理主机
     * @param proxyPort 代理端口
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String proxyHost, int proxyPort) {
        return genOkHttpClient(proxyHost, proxyPort, null, null);
    }

    /**
     * 根据代理拦截器生成okHttpClient
     *
     * @param proxyHost   代理主机
     * @param proxyPort   代理端口
     * @param interceptor 拦截器
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String proxyHost, int proxyPort, Interceptor interceptor) {
        return genOkHttpClient(proxyHost, proxyPort, null, null, interceptor);
    }

    /**
     * 根据证书生成okHttpClient
     *
     * @param certPath 证书地址
     * @param certPass 证书密匙
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String certPath, String certPass) {
        return genOkHttpClient(null, 0, certPath, certPass, new TrustAnyTrustManager());
    }

    /**
     * 根据证书拦截器生成okHttpClient
     *
     * @param certPath    证书地址
     * @param certPass    证书密匙
     * @param interceptor 拦截器
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String certPath, String certPass, Interceptor interceptor) {
        return genOkHttpClient(null, 0, certPath, certPass, new TrustAnyTrustManager(), interceptor);
    }

    /**
     * 根据证书生成okHttpClient
     *
     * @param certPath     证书地址
     * @param certPass     证书密匙
     * @param trustManager 证书接口
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String certPath, String certPass, X509TrustManager trustManager) {
        return genOkHttpClient(null, 0, certPath, certPass, trustManager);
    }

    /**
     * 根据证书拦截器生成okHttpClient
     *
     * @param certPath     证书地址
     * @param certPass     证书密匙
     * @param trustManager 证书接口
     * @param interceptor  拦截器
     * @return okhttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String certPath, String certPass, X509TrustManager trustManager, Interceptor interceptor) {
        return genOkHttpClient(null, 0, certPath, certPass, trustManager, interceptor);
    }

    /**
     * 根据代理证书生成okHttpClient,默认为Http代理
     *
     * @param proxyHost 代理主机
     * @param proxyPort 代理端口
     * @param certPath  证书地址
     * @param certPass  证书密匙
     * @return okHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String proxyHost, int proxyPort, String certPath, String certPass) {
        return genOkHttpClient(Proxy.Type.HTTP, proxyHost, proxyPort, certPath, certPass, new TrustAnyTrustManager(), null);
    }

    /**
     * 根据代理证书拦截器生成okHttpClient,默认为Http代理
     *
     * @param proxyHost   代理主机
     * @param proxyPort   代理端口
     * @param certPath    证书地址
     * @param certPass    证书密匙
     * @param interceptor 拦截器
     * @return okHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String proxyHost, int proxyPort, String certPath, String certPass, Interceptor interceptor) {
        return genOkHttpClient(Proxy.Type.HTTP, proxyHost, proxyPort, certPath, certPass, new TrustAnyTrustManager(), interceptor);
    }

    /**
     * 根据代理证书生成okHttpClient,默认为Http代理
     *
     * @param proxyHost    代理主机
     * @param proxyPort    代理端口
     * @param certPath     证书地址
     * @param certPass     证书密匙
     * @param trustManager 证书接口
     * @return okHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String proxyHost, int proxyPort, String certPath, String certPass, X509TrustManager trustManager) {
        return genOkHttpClient(Proxy.Type.HTTP, proxyHost, proxyPort, certPath, certPass, trustManager, null);
    }

    /**
     * 根据代理证书生成okHttpClient,默认为Http代理
     *
     * @param proxyHost    代理主机
     * @param proxyPort    代理端口
     * @param certPath     证书地址
     * @param certPass     证书密匙
     * @param trustManager 证书接口
     * @param interceptor  拦截器
     * @return okHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(String proxyHost, int proxyPort, String certPath, String certPass, X509TrustManager trustManager, Interceptor interceptor) {
        return genOkHttpClient(Proxy.Type.HTTP, proxyHost, proxyPort, certPath, certPass, trustManager, interceptor);
    }

    /**
     * 根据代理证书生成okHttpClient
     *
     * @param type        代理类型
     * @param proxyHost   代理主机
     * @param proxyPort   代理端口
     * @param certPath    证书地址
     * @param certPass    证书密匙
     * @param interceptor 拦截器
     * @return okHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(Proxy.Type type, String proxyHost, int proxyPort, String certPath, String certPass, Interceptor interceptor) {
        return genOkHttpClient(type, proxyHost, proxyPort, certPath, certPass, new TrustAnyTrustManager(), interceptor);
    }

    /**
     * 根据代理证书生成okHttpClient
     *
     * @param type         代理类型
     * @param proxyHost    代理主机
     * @param proxyPort    代理端口
     * @param certPath     证书地址
     * @param certPass     证书密匙
     * @param trustManager 证书接口
     * @param interceptor  拦截器
     * @return okHttpClient
     */
    public static OkHttpClient.Builder genOkHttpClient(Proxy.Type type, String proxyHost, int proxyPort, String certPath, String certPass, X509TrustManager trustManager, Interceptor interceptor) {
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        if (StringUtil.isNotEmpty(proxyHost)) {
            clientBuilder.proxy(new Proxy(type, new InetSocketAddress(proxyHost, proxyPort)));
        }
        if (StringUtil.isNotEmpty(certPath)) {
            clientBuilder.sslSocketFactory(getSslContext(certPath, certPass).getSocketFactory(), trustManager);
        }
        if (ObjectUtil.isNotEmpty(interceptor)) {
            clientBuilder.addInterceptor(interceptor);
        }
        return clientBuilder;
    }

    /**
     * 获取SSLContext
     *
     * @param certPath SSL证书路径
     * @param certPass SSL证书密匙
     * @return SSLContext
     */
    public static SSLContext getSslContext(String certPath, String certPass) {
        return getSslContext(certPath, certPass, new TrustAnyTrustManager());
    }

    public static SSLContext getSslContext(String certPath, String certPass, TrustManager trustManager) {
        try {
            KeyStore clientStore = KeyStore.getInstance("PKCS12");
            FileInputStream inputStream = new FileInputStream(certPath);
            char[] passArray = certPass.toCharArray();
            clientStore.load(inputStream, passArray);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(clientStore, passArray);
            KeyManager[] kms = kmf.getKeyManagers();
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kms, new TrustManager[]{trustManager}, new SecureRandom());
            return sslContext;
        } catch (Exception e) {
            throw new BusinessException(500, "证书设置异常", e);
        }
    }
}
